/*
* PDBHeuristic.cpp
*
*  Created on: 23/05/2011
*      Author: frandres
*/

#include "PDBHeuristic.h"


PDBHeuristic::PDBHeuristic(int _n, bool *_X)
{
	n       = _n;
	X       = _X;
	perm    = (int *) calloc(n,sizeof(int));
	Hsize   = 16;

	int i = 0;

	for(i = 15; i > (16-n); i--)
		Hsize *= i;

	H = (unsigned char*) malloc(Hsize*sizeof(unsigned char));

	memset(H, 81, Hsize);

}

PDBHeuristic::PDBHeuristic(int _n, bool *_X, char *filename)
{
	n       = _n;
	X       = _X;
	perm    = (int *) calloc(n,sizeof(int));
	Hsize   = 16;

	int i = 0;

	for(i = 15; i > (16-n); i--)
		Hsize *= i;

	H = (unsigned char*) malloc(Hsize*sizeof(unsigned char));

	memset(H, 81, Hsize);

	ifstream file (filename);

	i = 0;

	cout << "Leyendo archivo " << filename << endl;

	if (file.is_open())
	{
		while ( file.good() && !file.eof())
		{
			int x;
			file >> x;
			H[i] = x;
			i++;
		}

		file.close();
	}
	else
	{
		cout << "Error abriendo el archivo. Recuerde que debe ejecutar ./main GEN primero antes de usar la heuristica PDB." << endl;
		exit(-1);
	}

	cout << "Fin lectura del archivo " << filename << endl;

}

PDBHeuristic::~PDBHeuristic()
{

	free(X);
	free(perm);

}

unsigned short int PDBHeuristic::calculateHeuristic(int invBoard[])
{

	int i, j = 0, d, fact = 17-n, result = 0, act = fact;

	for(i = 0; i < 16; i++)
		if(!X[i])
			perm[j++] = invBoard[i];

	d = perm[n-1];

	for(j = n-2; j >= 0; j--)
		if(perm[n-1] > perm[j])
			d--;

	result += d;

	for(i = n-2; i >= 0; i--)
	{

		d = perm[i];

		j = i-1;

		for(; j >= 0; j--)
			if(perm[i] > perm[j])
				d--;

		d *= fact;

		fact *= act+1;

		act++;

		result += d;

	}

	return H[result];

}

unsigned int PDBHeuristic::getRank(int invBoard[])
{

	int i, j = 0, d, fact = 17-n, result = 0, act = fact;

	for(i = 0; i < 16; i++)
		if(!X[i])
			perm[j++] = invBoard[i];

	d = perm[n-1];

	for(j = n-2; j >= 0; j--)
		if(perm[n-1] > perm[j])
			d--;

	result += d;

	for(i = n-2; i >= 0; i--)
	{

		d = perm[i];

		j = i-1;

		for(; j >= 0; j--)
			if(perm[i] > perm[j])
				d--;

		d *= fact;

		fact *= act+1;

		act++;

		result += d;

	}

	return result;

}

